package com.mmc.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.digest.BCrypt;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mmc.entity.User;
import com.mmc.entity.Role;
import com.mmc.mapper.UserMapper;
import com.mmc.mapper.UserRoleMapper;
import com.mmc.service.UserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;

/**
 * 用户服务实现类
 *
 * @author kunfe
 * @since 2024-01-01
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    private final UserMapper userMapper;
    private final UserRoleMapper userRoleMapper;

    @Override
    public Page<User> getUserPage(Page<User> page, String username, String realName, String phone, String email, Integer status, Long deptId) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<User>()
                .like(ObjectUtil.isNotEmpty(username), User::getUsername, username)
                .like(ObjectUtil.isNotEmpty(realName), User::getRealName, realName)
                .like(ObjectUtil.isNotEmpty(phone), User::getPhone, phone)
                .like(ObjectUtil.isNotEmpty(email), User::getEmail, email)
                .eq(ObjectUtil.isNotNull(status), User::getStatus, status)
                .eq(ObjectUtil.isNotNull(deptId), User::getDeptId, deptId)
                .orderByDesc(User::getCreateTime);
        
        return page(page, wrapper);
    }

    @Override
    public User getUserByUsername(String username) {
        return userMapper.selectByUsername(username);
    }

    @Override
    public User getUserByEmail(String email) {
        return userMapper.selectByEmail(email);
    }

    @Override
    public User getUserByPhone(String phone) {
        return userMapper.selectByPhone(phone);
    }

    @Override
    public boolean existsUsername(String username, Long excludeId) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<User>()
                .eq(User::getUsername, username)
                .ne(ObjectUtil.isNotNull(excludeId), User::getId, excludeId);
        return count(wrapper) > 0;
    }

    @Override
    public boolean existsEmail(String email, Long excludeId) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<User>()
                .eq(User::getEmail, email)
                .ne(ObjectUtil.isNotNull(excludeId), User::getId, excludeId);
        return count(wrapper) > 0;
    }

    @Override
    public boolean existsPhone(String phone, Long excludeId) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<User>()
                .eq(User::getPhone, phone)
                .ne(ObjectUtil.isNotNull(excludeId), User::getId, excludeId);
        return count(wrapper) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean createUser(User user) {
        // 检查用户名是否存在
        if (existsUsername(user.getUsername(), null)) {
            throw new RuntimeException("用户名已存在");
        }
        
        // 检查邮箱是否存在
        if (ObjectUtil.isNotEmpty(user.getEmail()) && existsEmail(user.getEmail(), null)) {
            throw new RuntimeException("邮箱已存在");
        }
        
        // 检查手机号是否存在
        if (ObjectUtil.isNotEmpty(user.getPhone()) && existsPhone(user.getPhone(), null)) {
            throw new RuntimeException("手机号已存在");
        }
        
        // 密码加密
        if (ObjectUtil.isNotEmpty(user.getPassword())) {
            user.setPassword(BCrypt.hashpw(user.getPassword(), BCrypt.gensalt()));
            user.setPasswordUpdateTime(LocalDateTime.now());
        }
        
        // 设置默认值
        if (user.getStatus() == null) {
            user.setStatus(1);
        }
        if (user.getUserType() == null) {
            user.setUserType(1);
        }
        
        boolean result = save(user);
        
        // 分配角色
        if (result && CollUtil.isNotEmpty(user.getRoleIds())) {
            assignRoles(user.getId(), user.getRoleIds());
        }
        
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateUser(User user) {
        User existUser = getById(user.getId());
        if (existUser == null) {
            throw new RuntimeException("用户不存在");
        }
        
        // 检查用户名是否存在
        if (!existUser.getUsername().equals(user.getUsername()) && existsUsername(user.getUsername(), user.getId())) {
            throw new RuntimeException("用户名已存在");
        }
        
        // 检查邮箱是否存在
        if (ObjectUtil.isNotEmpty(user.getEmail()) && !user.getEmail().equals(existUser.getEmail()) && existsEmail(user.getEmail(), user.getId())) {
            throw new RuntimeException("邮箱已存在");
        }
        
        // 检查手机号是否存在
        if (ObjectUtil.isNotEmpty(user.getPhone()) && !user.getPhone().equals(existUser.getPhone()) && existsPhone(user.getPhone(), user.getId())) {
            throw new RuntimeException("手机号已存在");
        }
        
        // 密码处理
        if (ObjectUtil.isNotEmpty(user.getPassword())) {
            user.setPassword(BCrypt.hashpw(user.getPassword(), BCrypt.gensalt()));
            user.setPasswordUpdateTime(LocalDateTime.now());
        } else {
            // 不更新密码字段，从User对象中移除密码相关字段
            user.setPassword(null);
            user.setPasswordUpdateTime(null);
        }
        
        boolean result = updateById(user);
        
        // 更新角色
        if (result && user.getRoleIds() != null) {
            assignRoles(user.getId(), user.getRoleIds());
        }
        
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteUser(Long userId) {
        // 检查是否为当前登录用户
        Long currentUserId = StpUtil.getLoginIdAsLong();
        if (currentUserId.equals(userId)) {
            throw new RuntimeException("不能删除当前登录用户");
        }
        
        // 删除用户角色关联
        userRoleMapper.deleteByUserId(userId);
        
        return removeById(userId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean batchDeleteUser(List<Long> userIds) {
        if (CollUtil.isEmpty(userIds)) {
            return false;
        }
        
        // 检查是否包含当前登录用户
        Long currentUserId = StpUtil.getLoginIdAsLong();
        if (userIds.contains(currentUserId)) {
            throw new RuntimeException("不能删除当前登录用户");
        }
        
        // 删除用户角色关联
        userRoleMapper.batchDeleteByUserIds(userIds);
        
        return removeByIds(userIds);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean changeStatus(Long userId, Integer status) {
        // 检查是否为当前登录用户
        Long currentUserId = StpUtil.getLoginIdAsLong();
        if (currentUserId.equals(userId)) {
            throw new RuntimeException("不能禁用当前登录用户");
        }
        
        User user = new User();
        user.setId(userId);
        user.setStatus(status);
        
        return updateById(user);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean resetPassword(Long userId, String newPassword) {
        User user = new User();
        user.setId(userId);
        user.setPassword(BCrypt.hashpw(newPassword, BCrypt.gensalt()));
        user.setPasswordUpdateTime(LocalDateTime.now());
        
        return updateById(user);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean changePassword(Long userId, String oldPassword, String newPassword) {
        User user = getById(userId);
        if (user == null) {
            throw new RuntimeException("用户不存在");
        }
        
        // 验证原密码
        if (!BCrypt.checkpw(oldPassword, user.getPassword())) {
            throw new RuntimeException("原密码错误");
        }
        
        // 检查新密码是否与原密码相同
        if (BCrypt.checkpw(newPassword, user.getPassword())) {
            throw new RuntimeException("新密码不能与原密码相同");
        }
        
        user.setPassword(BCrypt.hashpw(newPassword, BCrypt.gensalt()));
        user.setPasswordUpdateTime(LocalDateTime.now());
        
        return updateById(user);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean assignRoles(Long userId, List<Long> roleIds) {
        // 删除原有角色
        userRoleMapper.deleteByUserId(userId);
        
        // 分配新角色
        if (CollUtil.isNotEmpty(roleIds)) {
            return userRoleMapper.batchInsert(userId, roleIds) > 0;
        }
        
        return true;
    }

    @Override
    public List<Long> getUserRoleIds(Long userId) {
        return userRoleMapper.selectRoleIdsByUserId(userId);
    }

    @Override
    public List<Role> getUserRoles(Long userId) {
        return userRoleMapper.selectRolesByUserId(userId);
    }

    @Override
    public boolean updateProfile(Long userId, User user) {
        User existUser = getById(userId);
        if (existUser == null) {
            throw new RuntimeException("用户不存在");
        }
        
        // 检查邮箱是否存在
        if (ObjectUtil.isNotEmpty(user.getEmail()) && 
            !user.getEmail().equals(existUser.getEmail()) && 
            existsEmail(user.getEmail(), userId)) {
            throw new RuntimeException("邮箱已存在");
        }
        
        // 检查手机号是否存在
        if (ObjectUtil.isNotEmpty(user.getPhone()) && 
            !user.getPhone().equals(existUser.getPhone()) && 
            existsPhone(user.getPhone(), userId)) {
            throw new RuntimeException("手机号已存在");
        }
        
        // 只允许更新个人信息字段
        User updateUser = new User();
        updateUser.setId(userId);
        updateUser.setRealName(user.getRealName());
        updateUser.setNickname(user.getNickname());
        updateUser.setEmail(user.getEmail());
        updateUser.setPhone(user.getPhone());
        updateUser.setGender(user.getGender());
        updateUser.setBirthday(user.getBirthday());
        updateUser.setIntro(user.getIntro());
        
        return updateById(updateUser);
    }

    @Override
    public boolean updateAvatar(Long userId, String avatar) {
        User user = new User();
        user.setId(userId);
        user.setAvatar(avatar);
        
        return updateById(user);
    }

    @Override
    public List<User> getUsersByDeptId(Long deptId) {
        return list(new LambdaQueryWrapper<User>()
                .eq(User::getDeptId, deptId)
                .eq(User::getStatus, 1)
                .orderByAsc(User::getCreateTime));
    }

    @Override
    public List<User> getUsersByRoleId(Long roleId) {
        return userRoleMapper.selectUsersByRoleId(roleId);
    }

    @Override
    public boolean importUsers(List<User> users) {
        if (CollUtil.isEmpty(users)) {
            return false;
        }
        
        // 批量检查和处理
        for (User user : users) {
            // 检查必填字段
            if (ObjectUtil.isEmpty(user.getUsername())) {
                throw new RuntimeException("用户名不能为空");
            }
            
            // 检查重复
            if (existsUsername(user.getUsername(), null)) {
                throw new RuntimeException("用户名 " + user.getUsername() + " 已存在");
            }
            
            // 设置默认密码
            if (ObjectUtil.isEmpty(user.getPassword())) {
                user.setPassword("123456");
            }
            
            // 密码加密
            user.setPassword(BCrypt.hashpw(user.getPassword(), BCrypt.gensalt()));
            user.setPasswordUpdateTime(LocalDateTime.now());
            
            // 设置默认值
            if (user.getStatus() == null) {
                user.setStatus(1);
            }
            if (user.getUserType() == null) {
                user.setUserType(1);
            }
        }
        
        return saveBatch(users);
    }

    @Override
    public List<User> exportUsers(String username, String realName, String phone, String email, Integer status, Long deptId) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<User>()
                .like(ObjectUtil.isNotEmpty(username), User::getUsername, username)
                .like(ObjectUtil.isNotEmpty(realName), User::getRealName, realName)
                .like(ObjectUtil.isNotEmpty(phone), User::getPhone, phone)
                .like(ObjectUtil.isNotEmpty(email), User::getEmail, email)
                .eq(ObjectUtil.isNotNull(status), User::getStatus, status)
                .eq(ObjectUtil.isNotNull(deptId), User::getDeptId, deptId)
                .orderByDesc(User::getCreateTime);
        
        return list(wrapper);
    }
} 